#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <cerrno>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <functional>
#include <signal.h>
#include <poll.h>
#include "logMessage.hpp"
#include "Sock.hpp"
#include <fcntl.h>
#define gport 8080
#define default_sort -1
namespace select_ns
{
    using func_t = function<string(const string &)>;
    static const int num = 1024;

    class PollServer
    {
    public:
        PollServer(func_t func, const uint16_t &port = gport) : _port(port), _listensort(-1), _func(func), _fds(nullptr)
        {
        }
        ~PollServer()
        {
            if (_listensort > 0)
                close(_listensort);
        }
        void Print()
        {
            for (int i = 0; i < num; i++)
            {
                if (_fds[i].fd != default_sort)
                {
                    cout << "fd list :" << _fds[i].fd << endl;
                }
            }
        }
        // events：需要监视文件描述符上的哪些事件。
        // revents：poll函数返回时告知用户该文件描述符上的哪些事件已经就绪。
        void Recver(int pos)
        {
            // 接收网络发来的东西,并发回去
            logMessage(NORMAL, "Recver start");
            char buffer[1024];
            // 此时是select发来信号让我们调用recv，所以肯定不会阻塞
            ssize_t n = recv(_fds[pos].fd, buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                buffer[n] = 0;
                logMessage(NORMAL, "recv success");
            }
            else if (n == 0)
            {
                // 表示用户端退出
                close(_fds[pos].fd);
                _fds[pos].fd = default_sort;
                _fds[pos].events = 0;
                _fds[pos].revents = 0;
                logMessage(NORMAL, "client quit");
                return;
            }
            else
            {
                logMessage(FATAL, "recv err :%s", strerror(errno));
                close(_fds[pos].fd);
                return;
            }
            string ret = _func(buffer);
            cout << ret << endl;
            write(_fds[pos].fd, ret.c_str(), ret.size());
        }
        void Accepter()
        {
            string client_ip;
            uint16_t client_port;
            // accept得到的sock就是后续文件操作的“文件指针”
            int sock = Sock::Accept(_listensort, &client_ip, &client_port);
            logMessage(NORMAL, "accept sucess [%s][%d]", client_ip.c_str(), client_port);
            // 把新得到的sock加入select让他帮我管理
            int i = 0;
            for (; i < num; i++)
            {
                if (_fds[i].fd == default_sort)
                    break;
            }
            if (i == num)
            {
                logMessage(WARING, "is full,you need to wait");
                close(sock);
            }
            else
            {
                _fds[i].fd = sock;
                _fds[i].events = POLLIN;
                _fds[i].revents = 0;
            }
            Print();
        }
        void HanderEvent()
        {
            // accept
            for (int i = 0; i < num; i++)
            {
                if (_fds[i].fd == default_sort)
                    continue;
                if (!(_fds[i].events & POLLIN))
                    continue;
                if (_fds[i].fd == _listensort && (_fds[i].revents & POLLIN))
                {
                    Accepter();
                }
                else if (_fds[i].revents & POLLIN)
                {
                    Recver(i);
                }
            }
        }
        void Init()
        {
            _listensort = Sock::Socket();
            Sock::Bind(_listensort, _port);
            Sock::Listen(_listensort);
            _fds = new struct pollfd[num];
            for (int i = 0; i < num; i++)
            {
                _fds[i].fd = default_sort;
            }
            _fds[0].fd = _listensort;
            _fds[0].events = POLLIN;
            _fds[0].revents = 0;
        }
        void start()
        {
            while (1)
            {
                // 返回就绪的fd个数
                int n = poll(_fds, num, 1000);
                switch (n)
                {
                case 0:
                    logMessage(NORMAL, "time out....");
                    break;
                case -1:
                    logMessage(WARING, "poll err,errString :%s", strerror(errno));
                    break;
                default:
                    // 说明事件就绪了
                    logMessage(NORMAL, "get a new link..");
                    HanderEvent();
                    break;
                }
            }
        }

    private:
        int _port;
        int _listensort;
        struct pollfd *_fds;
        func_t _func;
    };
}